package com.example.project.projectspringcloud.service.impl.order;


import com.example.project.projectspringcloud.common.Constants;
import com.example.project.projectspringcloud.common.alipay.Payment;
import com.example.project.projectspringcloud.common.alipay.SignatureHelper;
import com.example.project.projectspringcloud.dao.sys.DictionaryMapper;
import com.example.project.projectspringcloud.dao.sys.SysConfigMapper;
import com.example.project.projectspringcloud.entity.order.Order;
import com.example.project.projectspringcloud.entity.sys.Dictionary;
import com.example.project.projectspringcloud.entity.sys.SysConfig;
import com.example.project.projectspringcloud.service.order.AlipayService;
import com.example.project.projectspringcloud.service.sys.SysDictionaryService;
import com.example.project.projectspringcloud.utils.WebUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * 支付宝 支付service 实现
 *
 * @author www.inxedu.com
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class AlipayServiceImpl implements AlipayService {

    protected static final String ERROR = "/500";

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private SysConfigMapper sysConfigMapper;

    @Autowired
    private DictionaryMapper dictionaryMapper;

    /**
     * 前往支付
     * ==============================================================================
     *
     * @param request
     * @param response
     * @param order
     * @return
     */
    @Override
    public String gotoAlipay(HttpServletRequest request, HttpServletResponse response, Order order) {
        try {
            logger.info("Get Alipay redirect URL, param sourceMap:" + order);

            // 获得支付宝配置
            Map<String, String> websitemap = getAlipayInfo();
            // 订单支付订单号
            String requestId = order.getNo();
            // 支付接口（不可以修改）
            String paygateway = "https://mapi.alipay.com/gateway.do?";
            // 快速付款交易服务（不可以修改）
            String service = "create_direct_pay_by_user";
            // 文件加密机制（不可以修改）
            String signType = "MD5";
            // 商户网站订单（也就是外部订单号，是通过客户网站传给支付宝，不可以重复）
            // String outTradeNo = guidGeneratorService.gainCode("PAY", true);
            // 商户网站订单（也就是外部订单号，是通过客户网站传给支付宝，不可以重复） 用时间戳代替了
            String outTradeNo = requestId;
            // （不可以修改）
            String inputCharset = Constants.Order.ALIPAY_INPUT_CHARSET;
            // partner和key提取方法：登录签约支付宝账户--->点击“商家服务”就可以看到
            // 支付宝合作伙伴id
            String partner = websitemap.get("alipaypartnerID");
            // 支付宝安全校验码(账户内提取)
            String key = websitemap.get("alipaykey");
            String body = WebUtil.getCurrentUser().getId() + "-" + requestId + "-" + outTradeNo;
            // 商品描述，推荐格式：商品名称（订单编号：订单编号）
            String totalFee = order.getTotalPrice().toString();
            // 订单总价,差价尚须银行支付的金额
            // totalFee = String.valueOf(totalFee);
            // 支付宝类型.1代表商品购买（目前填写1即可，不可以修改）
            String paymentType = "1";
            // 卖家支付宝帐户
            String sellerEmail = websitemap.get("sellerEmail");
            // subject 商品说明
            String subject = String.format("%s: %s - %s", Constants.Order.COMPANY_NAME,
                    dictionaryMapper.selectOne(new Dictionary("order-type", order.getType())).getName(),
                    dictionaryMapper.selectOne(new Dictionary("video-type", order.getOrderDetail().getVideoType())).getName());
            // 扩展信息,存用户id和requestId.重要，必须存
            String extraCommonParam = WebUtil.getCurrentUser().getId() + "," + requestId;
            // 商品地址
            String showUrl = String.format("%s%s%s", request.getAttribute("ctx"), "/order/get/", order.getId());
            // 回调的地址, 根据集成的网站而定
            String path = (String) request.getAttribute("ctx");
            // 通知接收URL(本地测试时，服务器返回无法测试)
            // String notifyUrl = path + "/zfbpay/order/alipaynotify/1";
            String notifyUrl = path + "/pay/callback/1/notify";
            // 支付完成后跳转返回的网址URL
            // String returnUrl = path + "/zfbpay/order/alipaynotify/2";
            String returnUrl = path + "/pay/callback/1/return";
            // 注意以上两个地址 要用 http://格式的完整路径
            // 以下两个参数paymethod和defaultbank可以选择不使用，如果不使用需要注销，并在Payment类的方法中也要注销
            String defaultbank = request.getParameter("defaultbank");

            String payMethod = "";
            if (StringUtils.isNotEmpty(defaultbank)) {
                payMethod = Constants.Order.PAY_METHOD_BANK;
            } else {
                defaultbank = null;
                payMethod = Constants.Order.PAY_METHOD_DIRECT;
            }

            String submitUrl = Payment.createUrl(paygateway, service, signType, outTradeNo, inputCharset, partner, key,
                    showUrl, body, totalFee, paymentType, sellerEmail, subject, notifyUrl, returnUrl, payMethod,
                    defaultbank, extraCommonParam);
            logger.info("Alipay submit RUL:" + submitUrl);
            return submitUrl;
        } catch (Exception e) {
            logger.error(request.getContextPath(), e);
            StackTraceElement[] messages = e.getStackTrace();
            if (messages != null && messages.length > 0) {
                StringBuffer buffer = new StringBuffer();
                buffer.append(e.toString()).append("<br/>");
                for (int i = 0; i < messages.length; i++) {
                    buffer.append(messages[i].toString()).append("<br/>");
                }
                request.setAttribute("myexception", buffer.toString());
            }
            return ERROR;
        }
    }

    /**
     * 获取支付宝系统配置
     * ==============================================================================
     *
     * @return
     */
    @Override
    public Map<String, String> getAlipayInfo() {
        List<SysConfig> alipayConfigList = sysConfigMapper.selectAll(new SysConfig(Constants.SysConfigType.SYS_CONFIG_TYPE_PAY_ALI));

        if (alipayConfigList != null && alipayConfigList.size() > 0) {
            Map<String, String> websitemap = new HashMap<String, String>();
            alipayConfigList.forEach(t -> {
                websitemap.put(t.getColumn(), t.getValue());
            });

            return websitemap;
        }

        return null;
    }

    /**
     * 支付宝返回数据的校验
     * ==============================================================================
     *
     * @param request
     * @return
     * @throws Exception
     */
    @Override
    public boolean getAlipayCheckInfo(HttpServletRequest request) throws Exception {
        // 获得支付宝配置
        Map<String, String> websitemap = getAlipayInfo();
        // 支付宝合作伙伴id
        String partner = websitemap.get("alipaypartnerID");
        // 支付宝安全校key
        String privateKey = websitemap.get("alipaykey");
        String alipayNotifyURL = "http://notify.alipay.com/trade/notify_query.do?"
                + "partner=" + partner + "&notify_id="
                + request.getParameter("notify_id");
        String responseTxt = check(alipayNotifyURL);
        // 效验失败
        if (!"true".equals(responseTxt)) {
            logger.info("支付宝返回数据效验失败  ---responseTxt---" + responseTxt);
            return false;
        }
        Map<String, Object> params = new HashMap<String, Object>();
        // 获得POST 过来参数设置到新的params中
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 中文商品名称 转码
            if ("subject".equals(name.trim())) {
                valueStr = URLDecoder.decode(valueStr, "gb2312");
            } else {
                // 乱码解决，这段代码在出现乱码时使用,但是不一定能解决所有的问题，所以建议写过滤器实现编码控制。 如果mysign和sign不相等也可以使用这段代码转化
                valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
            }
            params.put(name, valueStr);
        }
        // 验证加密签名
        String mysign = SignatureHelper.sign(params, privateKey);
        if (!mysign.equals(request.getParameter("sign"))) {
            logger.info("验证加密签名  ---mysign---" + request.getParameter("sign"));
            logger.info("验证加密签名  ---params---" + params);
            return false;
        }
        return true;
    }

    private String check(String urlvalue) {
        String inputLine = "";

        try {
            URL e = new URL(urlvalue);
            HttpURLConnection urlConnection = (HttpURLConnection) e.openConnection();
            BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
            inputLine = in.readLine().toString();
        } catch (Exception var5) {
            var5.printStackTrace();
        }

        return inputLine;
    }
}